package main

import (
	"fmt"
	"github.com/fatih/structs"
	"reflect"
)

//// UserInfo 用户信息
//type UserInfo struct {
//	Name string `json:"name" structs:"name"`
//	Age  int    `json:"age" structs:"age"`
//}

func demo1() {
	u1 := UserInfo{
		Name: "ybl",
		Age:  1011,
	}
	//b,_:=json.Marshal(u1)
	var m map[string]interface{}
	//json.Unmarshal(b,&m)
	m, _ = ToMap(u1, "json")
	for k, v := range m {
		fmt.Printf("key:%v value:%v type:%T\n", k, v, v)
	}
}
func ToMap(in interface{}, tagName string) (map[string]interface{}, error) {
	out := make(map[string]interface{})
	v := reflect.ValueOf(in)
	if v.Kind() == reflect.Ptr {
		v = v.Elem() //这里赋值之后就是相当于取值了 从指针变成了struct ,如果你不通过反射修改值 没必要这样做
	}
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)
	}
	t := reflect.TypeOf(in) //NumField of non-struct type *main.UserInfo

	for i := 0; i < t.NumField(); i++ {
		fi := t.Field(i)
		if tagvalue := fi.Tag.Get(tagName); tagvalue != "" {
			out[tagvalue] = v.Field(i).Interface()
		}
	}
	return out, nil
}

//使用轮子
func demo3() {
	u1 := UserInfo{
		Name: "ybl",
		Age:  1011,
	}
	m3 := structs.Map(u1)
	for k, v := range m3 {
		fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)
	}
}

// UserInfo 用户信息
type UserInfo struct {
	Profile `json:"profile" structs:"profile"`
	Name    string `json:"name" structs:"name"`
	Age     int    `json:"age" structs:"age"`
}

// Profile 配置信息
type Profile struct {
	Hobby string `json:"hobby" structs:"hobby"`
}

func demo4() {
	u1 := UserInfo{Name: "ybl", Age: 18, Profile: Profile{"游泳"}}
	m3 := structs.Map(u1)
	for k, v := range m3 {
		fmt.Printf("key:%v value:%v value type:%T\n", k, v, v)
	}
}
func ToMap2(in interface{}, tagName string) (map[string]interface{}, error) {
	v := reflect.ValueOf(in)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("ToMap only accepts struct or struct pointer; got %T", v)
	}
	out := make(map[string]interface{})
	queue := make([]interface{}, 0, 1)
	queue = append(queue, in)
	for len(queue) > 0 {
		v := reflect.ValueOf(queue[0])
		if v.Kind() == reflect.Ptr {
			v = v.Elem()
		}
		queue = queue[1:]
		t := v.Type()
		for i := 0; i < t.NumField(); i++ {
			vi := v.Field(i)
			if vi.Kind() == reflect.Ptr {
				vi = vi.Elem()
				if vi.Kind() == reflect.Struct {
					queue = append(queue, vi.Interface())
				} else {
					ti := t.Field(i)
					if tagValue := ti.Tag.Get(tagName); tagValue != "" {
						// 存入map
						out[tagValue] = vi.Interface()
					}
				}
				continue
			}
			if vi.Kind() == reflect.Struct {
				queue = append(queue, vi.Interface())
				continue
			}
			// 一般字段
			ti := t.Field(i)
			if tagValue := ti.Tag.Get(tagName); tagValue != "" {
				// 存入map
				out[tagValue] = vi.Interface()
			}
		}
	}
	return out, nil
}

func demo5() {
	u1 := UserInfo{Name: "ybl", Age: 18, Profile: Profile{"游泳"}}
	var m map[string]interface{}
	m, _ = ToMap2(u1, "json")
	for k, v := range m {
		fmt.Printf("key:%v value:%v type:%T\n", k, v, v)
	}
}
func main() {
	//demo1()
	//demo3()
	//demo4()

	//demo5()
}
